package de.unidue.langtech.teaching.pp.example;

import java.util.Collection;

import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.fit.component.JCasAnnotator_ImplBase;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.JCas;

import de.unidue.langtech.teaching.pp.type.BaseTime;
import de.unidue.langtech.teaching.pp.type.TimexEvent;

/**
 * The RuleManager contains the timex rules. The more timex events are matched
 * correctly the better is the result. GoldTime is the value of the time
 * expression. If the time expression is detected correctly, the DetectedTime
 * has the same value as the GoldTime.
 */

public class RuleManager extends JCasAnnotator_ImplBase {

	// search for written numbers in the text
	// tryFindNumber("twenty weeks") = 20
	private int tryFindNumber(String v) {
		if (v.contains("one") || v.contains("first")) {
			return 1;
		} else if (v.contains("two") || v.contains("second")) {
			return 2;
		} else if (v.contains("three") || v.contains("third")) {
			return 3;
		} else if (v.contains("four") || v.contains("fourth")) {
			return 4;
		} else if (v.contains("five")) {
			return 5;
		} else if (v.contains("six")) {
			return 6;
		} else if (v.contains("seven")) {
			return 7;
		} else if (v.contains("eight")) {
			return 8;
		} else if (v.contains("nine")) {
			return 9;
		} else if (v.contains("ten")) {
			return 10;
		} else if (v.contains("twenty")) {
			return 20;
		} else {
			return -1;
		}
	}

	@Override
	public void process(JCas jcas) throws AnalysisEngineProcessException { 

		//gets timex Events from the jcan, until no timex Events is remaining
		Collection<TimexEvent> timexEvents = JCasUtil.select(jcas, TimexEvent.class);
		BaseTime basetime = JCasUtil.selectSingle(jcas, BaseTime.class);

		for (TimexEvent timexEvent : timexEvents) {

			String timexType = timexEvent.getTimexType();
			// timexText is the natural language in the <TIMEX3> tag
			// with .toLowerCase() we ignore the capitalization
			String timexText = timexEvent.getTimexText().toLowerCase();
			int basetimeYear = basetime.getBasetimeYear();
			int basetimeMonth = basetime.getBasetimeMonth();
			int basetimeDay = basetime.getBasetimeDay();
			String basetimeValue = basetime.getValue();
			// String.format[...] is basetime without time
			String basetimeDateOnly = String.format("%04d-%02d-%02d", 
					basetimeYear, basetimeMonth, basetimeDay);

			// if the timex type is TIME or DATE, the following rules are
			// important
			if ((timexType.equals("TIME")) || (timexType.equals("DATE"))) {
				if (timexText.contains("tomorrow")) {
					// if its the last day of the month, tomorrow is the next
					// month
					if (basetimeDay >= 30) {
						timexEvent.setDetectedValue(String.format(
								"%04d-%02d-%02d", basetimeYear,
								basetimeMonth + 1, 1));
					} else {
						// otherwise it's the next day in the same month
						timexEvent.setDetectedValue(String.format(
								"%04d-%02d-%02d", basetimeYear, basetimeMonth,
								basetimeDay + 1));
					}

				} else if (timexText.contains("yesterday")) {
					// if it's the first day of the month -> yesterday is the
					// last month
					if (basetimeDay == 1) {
						timexEvent.setDetectedValue(String.format(
								"%04d-%02d-%02d", basetimeYear,
								basetimeMonth - 1, 31));
					} else {
						// otherwise it's the day before in the same month
						timexEvent.setDetectedValue(String.format(
								"%04d-%02d-%02d", basetimeYear, basetimeMonth,
								basetimeDay - 1));
					}

					// for daytimes and seasons we need baseTimeDateOnly
					// (date without the time) and the special label
					// e.g. TEV is This EVening
				} else if (timexText.contains("morning")) {
					timexEvent.setDetectedValue(basetimeDateOnly + "TMO");
				} else if (timexText.contains("midday")) {
					timexEvent.setDetectedValue(basetimeDateOnly + "TMI");
				} else if (timexText.contains("evening")) {
					timexEvent.setDetectedValue(basetimeDateOnly + "TEV");
					
				} else if (timexText.contains("summer")) {
					timexEvent.setDetectedValue(basetimeYear + "-SU");
				} else if (timexText.contains("autumn") || (timexText.contains("fall"))) {
					timexEvent.setDetectedValue(basetimeYear + "-FA");
				} else if (timexText.contains("winter")) {
					timexEvent.setDetectedValue(basetimeYear + "-WI");
				} else if (timexText.contains("spring")) {
					timexEvent.setDetectedValue(basetimeYear + "-SP");
					
					// now search for present, past and future time expressions
				} else if (timexText.contains("now") || timexText.contains("current")) {
					timexEvent.setDetectedValue("PRESENT_REF");
				} else if (timexText.contains("recent") || timexText.contains("past")) {
					timexEvent.setDetectedValue("PAST_REF");
				} else if (timexText.contains("soon") || timexText.contains("future")) {
					timexEvent.setDetectedValue("FUTURE_REF");

				} else if (timexText.contains("last week")) {
					basetimeDay = basetimeDay - 7;
					timexEvent.setDetectedValue(String.format("%04d-%02d-%02d",
							basetimeYear, basetimeMonth, basetimeDay));
				} else if (timexText.contains("next week")) {
					basetimeDay = basetimeDay + 7;
					timexEvent.setDetectedValue(String.format("%04d-%02d-%02d",
							basetimeYear, basetimeMonth, basetimeDay));

				} else if (timexText.contains("this month")) {
					basetimeMonth = basetimeMonth + 0;
					timexEvent.setDetectedValue(basetimeMonth + "");	
				} else if (timexText.contains("last month")) {
					basetimeMonth = basetimeMonth - 1;
					timexEvent.setDetectedValue(String.format("%04d-%02d",
							basetimeYear, basetimeMonth));
				} else if (timexText.contains("next month")) {
					basetimeMonth = basetimeMonth + 1;
					timexEvent.setDetectedValue(String.format("%04d-%02d",
							basetimeYear, basetimeMonth));

				} else if (timexText.contains("this year")) {
					basetimeYear = basetimeYear + 0;
					//we need as String
					timexEvent.setDetectedValue(basetimeYear + "");	
				} else if (timexText.contains("next year")) {
					basetimeYear = basetimeYear + 1;
					timexEvent.setDetectedValue(basetimeYear + "");														
				} else if (timexText.contains("last year")) {
					basetimeYear = basetimeYear - 1;
					timexEvent.setDetectedValue(basetimeYear + "");
				} else if (timexText.contains("two years ago")) {
					basetimeYear = basetimeYear - 2;
					timexEvent.setDetectedValue(basetimeYear + "");
				} else if (timexText.contains("three years ago")) {
					basetimeYear = basetimeYear - 3;
					timexEvent.setDetectedValue(basetimeYear + "");
				} else if (timexText.contains("four years ago")) {
					basetimeYear = basetimeYear - 4;
					timexEvent.setDetectedValue(basetimeYear + "");
				} else if (timexText.contains("five years ago")) {
					basetimeYear = basetimeYear - 5;
					timexEvent.setDetectedValue(basetimeYear + "");

					// months
				} else if (timexText.equals("january")) {
					timexEvent.setDetectedValue(basetimeYear + "-01");
				} else if (timexText.equals("february")) {
					timexEvent.setDetectedValue(basetimeYear + "-02");
				} else if (timexText.equals("march")) {
					timexEvent.setDetectedValue(basetimeYear + "-03");
				} else if (timexText.equals("april")) {
					timexEvent.setDetectedValue(basetimeYear + "-04");
				} else if (timexText.equals("may")) {
					timexEvent.setDetectedValue(basetimeYear + "-05");
				} else if (timexText.equals("june")) {
					timexEvent.setDetectedValue(basetimeYear + "-06");
				} else if (timexText.equals("july")) {
					timexEvent.setDetectedValue(basetimeYear + "-07");
				} else if (timexText.equals("august")) {
					timexEvent.setDetectedValue(basetimeYear + "-08");
				} else if (timexText.equals("september")) {
					timexEvent.setDetectedValue(basetimeYear + "-09");
				} else if (timexText.equals("october")) {
					timexEvent.setDetectedValue(basetimeYear + "-10");
				} else if (timexText.equals("november")) {
					timexEvent.setDetectedValue(basetimeYear + "-11");
				} else if (timexText.equals("december")) {
					timexEvent.setDetectedValue(basetimeYear + "-12");

					/*
					 * source:
					 * http://stackoverflow.com/questions/7855994/java-regex
					 * -a-z-a-z-0-9-and check if the figures are numbers between
					 * 0 and 9. Then check if there a four numbers in a row at
					 * least four numbers in a row are probably a year
					 */
				} else if (timexText.matches("^[0-9]{4}$")) {
					timexEvent.setDetectedValue(timexText);
				} else {
					timexEvent.setDetectedValue(basetimeValue);
				}
				
				// // if the timex type is TIME or DATE, the following rules are
				// important
			} else if (timexType.equals("DURATION")
					|| (timexType.equals("SET"))) {
				if (timexText.contains("day")) {
					if (timexText.equals("day")) {
						timexEvent.setDetectedValue("P1D");

						// find number in the identified natural language and set the number to the detected value
					} else if (tryFindNumber(timexText) != -1) {
						timexEvent.setDetectedValue("P"
								+ tryFindNumber(timexText) + "D");
						// if nothing matches
					} else {
						timexEvent.setDetectedValue("PXD");
					}
					
					if (timexText.contains("week")) {
						timexEvent.setDetectedValue("P1W");
					} else if (timexText.contains("next")) {
						basetimeDay = basetimeDay + 7;
						// same as above
						if (basetimeDay >= 30) {
							basetimeDay = 1;
							basetimeMonth = basetimeMonth + 1;
						}
						timexEvent.setDetectedValue(String.format(
								"%04d-%02d-%02d", basetimeYear, basetimeMonth,
								basetimeDay));
					} else if (timexText.contains("last")) {
						basetimeDay = basetimeDay - 7;
						// same as above
						if (basetimeDay < 1) {
							basetimeDay = 31;
							basetimeMonth = basetimeMonth - 1;
						}
						timexEvent.setDetectedValue(String.format(
								"%04d-%02d-%02d", basetimeYear, basetimeMonth,
								basetimeDay));
					} else if (tryFindNumber(timexText) != -1) {
						timexEvent.setDetectedValue("P"
								+ tryFindNumber(timexText) + "W");
						// if nothing matches
					} else {
						timexEvent.setDetectedValue("PXW");
					}

					if (timexText.equals("month") 
							|| timexText.contains("every month")) {
						timexEvent.setDetectedValue("P1M");

					} else if (tryFindNumber(timexText) != -1) {
						timexEvent.setDetectedValue("P"
								+ tryFindNumber(timexText) + "M");
						// if nothing matches
					} else {
						timexEvent.setDetectedValue("PXM");
					}
					
				    if (timexText.equals("quarter") 
							|| timexText.contains("every quarter")) {
						timexEvent.setDetectedValue("P1Q");

					} else if (tryFindNumber(timexText) != -1) {
						timexEvent.setDetectedValue("P"
								+ tryFindNumber(timexText) + "Q");
						// if nothing matches
					} else {
						timexEvent.setDetectedValue("PXQ");
					}
					
				} else if (timexText.contains("year")) {
					if (timexText.equals("year")
						|| timexText.contains("every year")) {
						timexEvent.setDetectedValue("P1Y");
					} 
					
					 else if (tryFindNumber(timexText) != -1) {
						timexEvent.setDetectedValue("P"
								+ tryFindNumber(timexText) + "Y");
						// if nothing matches
					} else {
						timexEvent.setDetectedValue("PXY");
					}
				} else {
					// if nothing matches
					timexEvent.setDetectedValue("Sorry, no hit");
				}
			}
		}
	}
}
